package net.eyra.negocio.explotacion.mantenimiento;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import net.eyra.negocio.dao.ExplotacionDao;
import net.eyra.negocio.dao.EyraDaoException;
import net.eyra.negocio.entidades.explotacion.Lectura;
import net.eyra.negocio.entidades.explotacion.Tarificador;
import net.eyra.utiles.FormateoFechaException;
import net.eyra.utiles.Periodo;

public class ComprobarMedidas {

    private ExplotacionDao dao = null;
    private List<Lectura> lecturas_fechas_duplicadas_tm1 = null;
    private List<Lectura> lecturas_fechas_duplicadas_tm2 = null;
    private List<Lectura> lecturas_fechas_perdidas_tm1 = null;
    private List<Lectura> lecturas_fechas_perdidas_tm2 = null;
    private List<Lectura> lecturas_fechas_diferentes_tm1 = null;
    private List<Lectura> lecturas_fechas_diferentes_tm2 = null;
    private int num_lecturas_tm1 = 0;
    private int num_lecturas_tm2 = 0;
    private Lectura total_tm1 = null;
    private Lectura total_tm2 = null;
    private String nombreTarificador = null;

    public ComprobarMedidas() {
        dao = new ExplotacionDao();

    }

    public double TotalLecturas(int id_tarificador, Periodo periodo, boolean horarias) throws FormateoFechaException, EyraDaoException {
        Periodo _periodo = new Periodo(periodo);
        if (horarias) _periodo.AjustarPeriodoCurvas(Periodo.MEDIDA_TM1);
        else _periodo.AjustarPeriodoCurvas(Periodo.MEDIDA_TM2);
        return dao.TotalSumaLecturas(id_tarificador, _periodo, horarias);
    }

    public void ComprobarCurvas(int id_tarificador, Periodo periodo) throws FormateoFechaException, EyraDaoException {
        Periodo _periodo = new Periodo(periodo);
        boolean lectura_tm1_null = false;
        boolean lectura_tm2_null = false;

        final List<Lectura> lecturas_tm2 = dao.RecuperarLecturas(id_tarificador, _periodo, false);
        if (lecturas_tm2 != null) {
            lecturas_fechas_perdidas_tm2 = BuscarHuecosFechas(id_tarificador, lecturas_tm2, _periodo, false);
            lecturas_fechas_duplicadas_tm2 = BuscarFechasDuplicadas(lecturas_tm2);
            num_lecturas_tm2 = lecturas_tm2.size();
            nombreTarificador = lecturas_tm2.get(0).getTarificador().getNombre();
        } else lectura_tm2_null = true;

        final List<Lectura> lecturas_tm1 = dao.RecuperarLecturas(id_tarificador, _periodo, true);
        if (lecturas_tm1 != null) {
            lecturas_fechas_perdidas_tm1 = BuscarHuecosFechas(id_tarificador, lecturas_tm1, _periodo, true);
            lecturas_fechas_duplicadas_tm1 = BuscarFechasDuplicadas(lecturas_tm1);
            num_lecturas_tm1 = lecturas_tm1.size();
            nombreTarificador = lecturas_tm1.get(0).getTarificador().getNombre();
        } else lectura_tm1_null = true;

        final int numero_lecturas_mes = _periodo.getDatoFecha(Periodo.FECHA_FINAL, Periodo.DIA) * 24;

        if (!lectura_tm1_null && !lectura_tm2_null) {
            Lectura lectura_tm1;
            Lectura lectura_tm2_1;
            Lectura lectura_tm2_2;
            Lectura lectura_tm2_3;
            Lectura lectura_tm2_4;
            for (int x = 0; x < numero_lecturas_mes; x++) {
                lectura_tm1 = BuscarLecturaPorFecha(_periodo.getFecha_inicial(), lecturas_tm1);
                _periodo.setDatoFecha(Periodo.FECHA_INICIAL, Periodo.HORA, _periodo.getDatoFecha(Periodo.FECHA_INICIAL, Periodo.HORA) - 1);
                _periodo.setDatoFecha(Periodo.FECHA_INICIAL, Periodo.MINUTO, _periodo.getDatoFecha(Periodo.FECHA_INICIAL, Periodo.MINUTO) + 15);
                lectura_tm2_1 = BuscarLecturaPorFecha(_periodo.getFecha_inicial(), lecturas_tm2);
                _periodo.setDatoFecha(Periodo.FECHA_INICIAL, Periodo.MINUTO, _periodo.getDatoFecha(Periodo.FECHA_INICIAL, Periodo.MINUTO) + 15);
                lectura_tm2_2 = BuscarLecturaPorFecha(_periodo.getFecha_inicial(), lecturas_tm2);
                _periodo.setDatoFecha(Periodo.FECHA_INICIAL, Periodo.MINUTO, _periodo.getDatoFecha(Periodo.FECHA_INICIAL, Periodo.MINUTO) + 15);
                lectura_tm2_3 = BuscarLecturaPorFecha(_periodo.getFecha_inicial(), lecturas_tm2);
                _periodo.setDatoFecha(Periodo.FECHA_INICIAL, Periodo.MINUTO, _periodo.getDatoFecha(Periodo.FECHA_INICIAL, Periodo.MINUTO) + 15);
                lectura_tm2_4 = BuscarLecturaPorFecha(_periodo.getFecha_inicial(), lecturas_tm2);

                if ((lectura_tm1.getActiva_importada() != lectura_tm2_1.getActiva_importada() + lectura_tm2_2.getActiva_importada()
                        + lectura_tm2_3.getActiva_importada() + lectura_tm2_4.getActiva_importada())
                        || (lectura_tm1.getActiva_exportada() != lectura_tm2_1.getActiva_exportada() + lectura_tm2_2.getActiva_exportada()
                                + lectura_tm2_3.getActiva_exportada() + lectura_tm2_4.getActiva_exportada())
                        || (lectura_tm1.getReactiva_q1() != lectura_tm2_1.getReactiva_q1() + lectura_tm2_2.getReactiva_q1()
                                + lectura_tm2_3.getReactiva_q1() + lectura_tm2_4.getReactiva_q1())
                        || (lectura_tm1.getReactiva_q2() != lectura_tm2_1.getReactiva_q2() + lectura_tm2_2.getReactiva_q2()
                                + lectura_tm2_3.getReactiva_q2() + lectura_tm2_4.getReactiva_q2())
                        || (lectura_tm1.getReactiva_q3() != lectura_tm2_1.getReactiva_q3() + lectura_tm2_2.getReactiva_q3()
                                + lectura_tm2_3.getReactiva_q3() + lectura_tm2_4.getReactiva_q3())
                        || (lectura_tm1.getReactiva_q4() != lectura_tm2_1.getReactiva_q4() + lectura_tm2_2.getReactiva_q4()
                                + lectura_tm2_3.getReactiva_q4() + lectura_tm2_4.getReactiva_q4())) {
                    if (lecturas_fechas_diferentes_tm1 == null) {
                        lecturas_fechas_diferentes_tm1 = new ArrayList<Lectura>();
                        lecturas_fechas_diferentes_tm2 = new ArrayList<Lectura>();
                    }
                    lecturas_fechas_diferentes_tm1.add(lectura_tm1);
                    lecturas_fechas_diferentes_tm2.add(lectura_tm2_1);
                    lecturas_fechas_diferentes_tm2.add(lectura_tm2_2);
                    lecturas_fechas_diferentes_tm2.add(lectura_tm2_3);
                    lecturas_fechas_diferentes_tm2.add(lectura_tm2_4);
                }

                _periodo.setDatoFecha(Periodo.FECHA_INICIAL, Periodo.HORA, _periodo.getDatoFecha(Periodo.FECHA_INICIAL, Periodo.HORA) + 1);
            }
        }

        double imp = 0;
        double exp = 0;
        double rq1 = 0;
        double rq2 = 0;
        double rq3 = 0;
        double rq4 = 0;
        if (!lectura_tm1_null) {
            total_tm1 = new Lectura();
            for (Lectura lectura : lecturas_tm1) {
                imp += lectura.getActiva_importada();
                exp += lectura.getActiva_exportada();
                rq1 += lectura.getReactiva_q1();
                rq2 += lectura.getReactiva_q2();
                rq3 += lectura.getReactiva_q3();
                rq4 += lectura.getReactiva_q4();
            }
        }
        total_tm1.setActiva_exportada(exp);
        total_tm1.setActiva_importada(imp);
        total_tm1.setReactiva_q1(rq1);
        total_tm1.setReactiva_q2(rq2);
        total_tm1.setReactiva_q3(rq3);
        total_tm1.setReactiva_q4(rq4);

        if (!lectura_tm2_null) {
            total_tm2 = new Lectura();
            imp = 0;
            exp = 0;
            rq1 = 0;
            rq2 = 0;
            rq3 = 0;
            rq4 = 0;
            for (Lectura lectura : lecturas_tm2) {
                imp += lectura.getActiva_importada();
                exp += lectura.getActiva_exportada();
                rq1 += lectura.getReactiva_q1();
                rq2 += lectura.getReactiva_q2();
                rq3 += lectura.getReactiva_q3();
                rq4 += lectura.getReactiva_q4();
            }
        }
        total_tm2.setActiva_exportada(exp);
        total_tm2.setActiva_importada(imp);
        total_tm2.setReactiva_q1(rq1);
        total_tm2.setReactiva_q2(rq2);
        total_tm2.setReactiva_q3(rq3);
        total_tm2.setReactiva_q4(rq4);

    }

    public void CorregirMedida(int id_tarificador, int hora, String periodo) throws FormateoFechaException, EyraDaoException {
        final List<Lectura> lecturas = dao.RecuperarLecturas(id_tarificador, hora, periodo);
        double im = 0;
        double ex = 0;
        double r1 = 0;
        double r2 = 0;
        double r3 = 0;
        double r4 = 0;
        for (int x = 0; x < 3; x++) {
            im += lecturas.get(x).getActiva_importada();
            ex += lecturas.get(x).getActiva_exportada();
            r1 += lecturas.get(x).getReactiva_q1();
            r2 += lecturas.get(x).getReactiva_q2();
            r3 += lecturas.get(x).getReactiva_q3();
            r4 += lecturas.get(x).getReactiva_q4();
        }
        lecturas.get(3).setActiva_importada(lecturas.get(3).getActiva_importada() - im);
        lecturas.get(3).setActiva_exportada(lecturas.get(3).getActiva_exportada() - ex);
        lecturas.get(3).setReactiva_q1(lecturas.get(3).getReactiva_q1() - r1);
        lecturas.get(3).setReactiva_q2(lecturas.get(3).getReactiva_q2() - r2);
        lecturas.get(3).setReactiva_q3(lecturas.get(3).getReactiva_q3() - r3);
        lecturas.get(3).setReactiva_q4(lecturas.get(3).getReactiva_q4() - r4);

        dao.setLectura(lecturas.get(3));
    }

    public Date FechaUltimaActualizacionCuartoHoraria(int id_tarificador) throws EyraDaoException {
        return dao.getUltimaFechaRegistradaPorTarificador(id_tarificador, false);
    }

    public Date FechaUltimaActualizacionHoraria(int id_tarificador) throws EyraDaoException {
        return dao.getUltimaFechaRegistradaPorTarificador(id_tarificador, false);
    }

    public List<Lectura> getLecturas_fechas_diferentes_tm1() {
        return lecturas_fechas_diferentes_tm1;
    }

    public List<Lectura> getLecturas_fechas_diferentes_tm2() {
        return lecturas_fechas_diferentes_tm2;
    }

    public List<Lectura> getLecturas_fechas_duplicadas_tm1() {

        return lecturas_fechas_duplicadas_tm1;
    }

    public List<Lectura> getLecturas_fechas_duplicadas_tm2() {

        return lecturas_fechas_duplicadas_tm2;
    }

    public List<Lectura> getLecturas_fechas_perdidas_tm1() {

        return lecturas_fechas_perdidas_tm1;
    }

    public List<Lectura> getLecturas_fechas_perdidas_tm2() {

        return lecturas_fechas_perdidas_tm2;
    }

    public List<String> ListaUltimaActualizacionPorTarificadorEyra() throws FormateoFechaException, EyraDaoException {

        final List<Tarificador> _tarificadores = dao.ListaTarificadores(ExplotacionDao.TIPO_TARIFICADOR_PRIMARIO, true);
        final List<String> _lista = new ArrayList<String>();

        final Periodo _periodo = new Periodo();
        String _dato = null;
        for (int x = 0; x < _tarificadores.size(); x++) {
            final int _id_tarificador = _tarificadores.get(x).getId_tarificador();
            try {
                _periodo.setFecha_inicial(FechaUltimaActualizacionHoraria(_id_tarificador));
                _periodo.setFecha_final(FechaUltimaActualizacionCuartoHoraria(_id_tarificador));
                final String _fecha_tm1 = _periodo.getFechaFormateada(Periodo.FORMATO_FECHA_AAAA_MM_DD_HH_MM, Periodo.FECHA_INICIAL,
                                                                      Periodo.SEPARADOR_FECHA_GUION).substring(0, 16);
                final String _fecha_tm2 = _periodo.getFechaFormateada(Periodo.FORMATO_FECHA_AAAA_MM_DD_HH_MM, Periodo.FECHA_FINAL,
                                                                      Periodo.SEPARADOR_FECHA_GUION).substring(0, 16);
                _dato = _tarificadores.get(x).getNombre() + "|" + _fecha_tm1 + "|" + _fecha_tm2;
            } catch (final EyraDaoException e) {
                _dato = _tarificadores.get(x).getNombre() + "|No Hay Medidas|No Hay Medidas";
            }
            _lista.add(_dato);
        }

        return _lista;
    }

    public void setLecturas_fechas_diferentes_tm1(List<Lectura> lecturas_fechas_diferentes_tm1) {
        this.lecturas_fechas_diferentes_tm1 = lecturas_fechas_diferentes_tm1;
    }

    public void setLecturas_fechas_diferentes_tm2(List<Lectura> lecturas_fechas_diferentes_tm2) {
        this.lecturas_fechas_diferentes_tm2 = lecturas_fechas_diferentes_tm2;
    }

    public void setLecturas_fechas_duplicadas_tm1(List<Lectura> lecturas_fechas_duplicadas_tm1) {

        this.lecturas_fechas_duplicadas_tm1 = lecturas_fechas_duplicadas_tm1;
    }

    public void setLecturas_fechas_duplicadas_tm2(List<Lectura> lecturas_fechas_duplicadas_tm2) {

        this.lecturas_fechas_duplicadas_tm2 = lecturas_fechas_duplicadas_tm2;
    }

    public void setLecturas_fechas_no_encontradas_tm1(List<Lectura> lecturas_fechas_no_encontradas_tm1) {

        this.lecturas_fechas_perdidas_tm1 = lecturas_fechas_no_encontradas_tm1;
    }

    public void setLecturas_fechas_perdidas_tm1(List<Lectura> lecturas_fechas_perdidas_tm1) {

        this.lecturas_fechas_perdidas_tm1 = lecturas_fechas_perdidas_tm1;
    }

    public void setLecturas_fechas_perdidas_tm2(List<Lectura> lecturas_fechas_perdidas_tm2) {

        this.lecturas_fechas_perdidas_tm2 = lecturas_fechas_perdidas_tm2;
    }

    /**
     * @param fecha
     *            Fecha a comprobar
     * @param lecturas
     *            . Lista donde comprobar
     * @return. El número de veces que aparece la fecha en la List de lecturas
     */
    private int BuscarFechaDuplicada(Date fecha, List<Lectura> lecturas) {

        int coincidencias = 0;
        for (int x = 0; x < lecturas.size(); x++)
            if (fecha.compareTo(lecturas.get(x).getFecha()) == 0) coincidencias++;

        return coincidencias;
    }

    /**
     * Busca entre las lecturas si existe más de una con la misma fecha y hora
     * 
     * @param lecturas
     * @return. Lista de lecturas que aparecen con la misma fecha y hora
     */
    private List<Lectura> BuscarFechasDuplicadas(List<Lectura> lecturas) {

        List<Lectura> _lecturas_fechas_duplicadas = null;
        for (int x = 0; x < lecturas.size(); x++)
            if (_lecturas_fechas_duplicadas != null) { // En caso de que existan ya duplicados
                // Comprueba que no se haya buscado ya esa fecha
                if (BuscarFechaDuplicada(lecturas.get(x).getFecha(), _lecturas_fechas_duplicadas) == 0) // Busca si una fecha aparece mas de una vez
                                                                                                        // entre las lecturas
                    if (BuscarFechaDuplicada(lecturas.get(x).getFecha(), lecturas) > 1) _lecturas_fechas_duplicadas.add(lecturas.get(x));
            } else // Busca si una fecha aparece mas de una vez entre las lecturas
            if (BuscarFechaDuplicada(lecturas.get(x).getFecha(), lecturas) > 1) {
                if (_lecturas_fechas_duplicadas == null) _lecturas_fechas_duplicadas = new ArrayList<Lectura>();
                _lecturas_fechas_duplicadas.add(lecturas.get(x));
            }

        return _lecturas_fechas_duplicadas;
    }

    private List<Lectura> BuscarHuecosFechas(int id_tarificador, List<Lectura> lecturas, Periodo periodo, boolean horaria) {

        final Periodo _periodo = new Periodo(periodo);

        final int numero_horas_diarias = horaria ? 24 : 24 * 4;
        final int numero_lecturas_mes = _periodo.getDatoFecha(Periodo.FECHA_INICIAL, Periodo.DIAS_MES) * numero_horas_diarias;

        _periodo.setDatoFecha(Periodo.FECHA_FINAL, Periodo.DIA, _periodo.getDatoFecha(Periodo.FECHA_FINAL, Periodo.DIA) + 1);

        List<Lectura> _lecturas_huecos_fechas = null;
        for (int x = 0; x < numero_lecturas_mes; x++) {
            if (BuscarFechaDuplicada(_periodo.getFecha_inicial(), lecturas) == 0 && _periodo.getFecha_inicial().before(_periodo.getFecha_final())) {
                if (_lecturas_huecos_fechas == null) _lecturas_huecos_fechas = new ArrayList<Lectura>();
                final Lectura lectura = new Lectura();
                lectura.setFecha(_periodo.getFecha_inicial());
                lectura.setTarificador(new Tarificador(id_tarificador));
                _lecturas_huecos_fechas.add(lectura);
            }
            if (horaria) _periodo.setDatoFecha(Periodo.FECHA_INICIAL, Periodo.HORA, _periodo.getDatoFecha(Periodo.FECHA_INICIAL, Periodo.HORA) + 1);
            else _periodo.setDatoFecha(Periodo.FECHA_INICIAL, Periodo.MINUTO, _periodo.getDatoFecha(Periodo.FECHA_INICIAL, Periodo.MINUTO) + 15);
        }
        return _lecturas_huecos_fechas;
    }

    /**
     * @param fecha
     * @param lecturas
     * @return Regresa un objeto lectura de 'lecturas' para la fecha indicada o un objeto con todas las lecturas a cero en caso de no encontrarla
     */
    private Lectura BuscarLecturaPorFecha(Date fecha, List<Lectura> lecturas) {
        for (int x = 0; x < lecturas.size(); x++)
            if (fecha.compareTo(lecturas.get(x).getFecha()) == 0) return lecturas.get(x);
        final Lectura lectura = new Lectura();
        lectura.setFecha(fecha);
        return lectura;
    }

    public int getNum_lecturas_tm1() {
        return num_lecturas_tm1;
    }

    public int getNum_lecturas_tm2() {
        return num_lecturas_tm2;
    }

    public Lectura getTotal_tm1() {
        return total_tm1;
    }

    public Lectura getTotal_tm2() {
        return total_tm2;
    }

    public String getNombreTarificador() {
        return nombreTarificador;
    }
}
